
#include "CarProperties.h"

#include <android-base/parsedouble.h>
#include <android-base/parseint.h>

#include <sstream>

namespace vhal {

// Returns the current value of the car property `key`,
// or `default_value` if the property is empty or doesn't exist.
std::string CarProperties::GetProperty(const std::string& key, const std::string& default_value) {
    return mProperties.GetProperty(key, default_value);
}

// Returns true if the car property `key` has the value "1", "y", "yes", "on", or "true",
// false for "0", "n", "no", "off", or "false", or `default_value` otherwise.
bool CarProperties::GetBoolProperty(const std::string& key, bool default_value) {
    bool result = default_value;
    std::string value = GetProperty(key, "");
    if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
        result = true;
    } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
        result = false;
    }

    return result;
}

// Returns the signed integer corresponding to the car property `key`.
// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
// the optional bounds, returns `default_value`.
template <typename T>
T CarProperties::GetIntProperty(const std::string& key, T default_value, T min, T max) {
    T result;
    std::string value = GetProperty(key, "");
    if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
    return default_value;
}

// Returns the unsigned integer corresponding to the car property `key`.
// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
// the optional bound, returns `default_value`.
template <typename T>
T CarProperties::GetUintProperty(const std::string& key, T default_value, T max) {
    T result;
    std::string value = GetProperty(key, "");
    if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
    return default_value;
}

template int8_t CarProperties::GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
template int16_t CarProperties::GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
template int32_t CarProperties::GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
template int64_t CarProperties::GetIntProperty(const std::string&, int64_t, int64_t, int64_t);

template uint8_t CarProperties::GetUintProperty(const std::string&, uint8_t, uint8_t);
template uint16_t CarProperties::GetUintProperty(const std::string&, uint16_t, uint16_t);
template uint32_t CarProperties::GetUintProperty(const std::string&, uint32_t, uint32_t);
template uint64_t CarProperties::GetUintProperty(const std::string&, uint64_t, uint64_t);

// Returns the double corresponding to the car property `key`.
// If the property is empty, doesn't exist, doesn't have an double value, or is outside
// the optional bound, returns `default_value`.
double CarProperties::GetDoubleProperty(const std::string& key, double default_value, double min,
                                        double max) {
    double result;
    std::string value = GetProperty(key, "");
    if (!value.empty() && android::base::ParseDouble(value.c_str(), &result, min, max)) return result;
    return default_value;
}

// Sets the car property `key` to `value`.
// Note that car property setting is inherently asynchronous so a return value of `true`
// isn't particularly meaningful, and immediately reading back the value won't necessarily
// tell you whether or not your call succeeded. A `false` return value definitely means failure.
bool CarProperties::SetProperty(const std::string& key, const std::string& value) {
    mProperties.AddProperty(key, value);
    return true;
}

// Sets the car property `key` to `value`.
bool CarProperties::SetBoolProperty(const std::string& key, bool value) {
    std::ostringstream ostring;
    ostring << value;
    return SetProperty(key, ostring.str());
}

// Sets the car property `key` to `value`.
template <typename T>
bool CarProperties::SetIntProperty(const std::string& key, T value) {
    std::ostringstream ostring;
    ostring << value;
    return SetProperty(key, ostring.str());
}

// Sets the car property `key` to `value`.
template <typename T>
bool CarProperties::SetUintProperty(const std::string& key, T value) {
    std::ostringstream ostring;
    ostring << value;
    return SetProperty(key, ostring.str());
}
template bool CarProperties::SetIntProperty(const std::string&, int8_t);
template bool CarProperties::SetIntProperty(const std::string&, int16_t);
template bool CarProperties::SetIntProperty(const std::string&, int32_t);
template bool CarProperties::SetIntProperty(const std::string&, int64_t);

template bool CarProperties::SetUintProperty(const std::string&, uint8_t);
template bool CarProperties::SetUintProperty(const std::string&, uint16_t);
template bool CarProperties::SetUintProperty(const std::string&, uint32_t);
template bool CarProperties::SetUintProperty(const std::string&, uint64_t);

// Sets the car property `key` to `value`.
bool CarProperties::SetDoubleProperty(const std::string& key, double value) {
    std::ostringstream ostring;
    ostring << value;
    return SetProperty(key, ostring.str());
}

}  // namespace vhal
